package com.springboot2.security.base.security.config;

import com.springboot2.security.base.security.filter.MyFilterSecurityInterceptor;
import com.springboot2.security.base.security.handler.LoginSuccessHandler;
import com.springboot2.security.base.security.service.CustomAccessDeniedHandler;
import com.springboot2.security.base.security.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;

/**
 * @param
 * @author liucancan
 * @description security核心配置类
 * @return
 * @date 2018/12/7
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    UserDetailsService detailsService() {
        return new UserDetailsServiceImpl();
    }

    @Autowired
    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;

    @Bean
    @Primary
    public DefaultWebInvocationPrivilegeEvaluator customWebInvocationPrivilegeEvaluator() {
        return new DefaultWebInvocationPrivilegeEvaluator(myFilterSecurityInterceptor);
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return new CustomAccessDeniedHandler();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                // 访问：这些路径 无需登录认证权限
                .antMatchers("/registry", "/login").permitAll()
                // 其他所有资源都需要认证，登陆后访问
                .anyRequest().authenticated()
                //.antMatchers("/resources").hasAuthority("ADMIN") //登陆后之后拥有“ADMIN”权限才可以访问/hello方法，否则系统会出现“403”权限不足的提示
                .and()
                .formLogin()
                // 指定登录页是login
                .loginPage("/login")
                .permitAll()
                // 登录成功后可使用loginSuccessHandler()存储用户信息，可选。
                .successHandler(loginSuccessHandler())
                .and()
                .logout()
                .logoutUrl("/logout")
                // 退出登录后的默认网址是”/home”
                .logoutSuccessUrl("/login")
                .permitAll()
                .invalidateHttpSession(true).and()
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler());
    }

    /**
     * 配置过滤器，静态资源允许访问
     *
     * @param web
     * @return void
     * @author liucancan
     * @date 17:00 2018/12/7
     */
    @Override
    public void configure(WebSecurity web) {
        web.securityInterceptor(myFilterSecurityInterceptor);
        web.privilegeEvaluator(customWebInvocationPrivilegeEvaluator());
        web.ignoring().antMatchers("/plugins/**");
    }

    /**
     * 验证登录人用户和密码
     * 定义的bean
     * 这样在登录的时候就会使用我们选择编码方式进行验证
     *
     * @param auth
     * @return void
     * @author liucancan
     * @date 18:08 2018/12/7
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(detailsService()).passwordEncoder(new BCryptPasswordEncoder());
    }

    /**
     * 注入密码编码方式对象
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    public LoginSuccessHandler loginSuccessHandler() {
        return new LoginSuccessHandler();
    }
}